/*
===========================================================================
Copyright (C) 2007 Michael Levin <risujin@risujin.org>

This file is part of Tremulous.

Tremulous is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

Tremulous is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#include "cg_local.h"

/*
==================
CG_RelicText
==================
*/
const char *CG_RelicText( relic_t relic )
{
  switch( relic )
  {
  case RLC_NONE:
    return "";
  case RLC_DOUBLE:
    return "Double damage dealt and received";
  case RLC_HEAL:
    return "Regenerates but limits your health";
  case RLC_IMMUNE:
    return "The last relic you pick up";
  case RLC_AMMO:
    return "More ammo for spray and pray";
  case RLC_VAMPIRE:
    return "Heal by attacking players";
  case RLC_BUILDER:
    return "Fast builder, slow walker";
  case RLC_HALF:
    return "Half damage dealt and received";
  case RLC_RESURRECT:
    return "Resurrect with low health once";
  case RLC_INVISIBLE:
    return "Invisible until combat with another player";
  case RLC_RADIATION:
    return "Damages everything around you";
  case RLC_GRAVITY:
    return "Low gravity";
  case RLC_ICE:
    return "Tremulous on ice";
  case RLC_BREAKER:
    return "Ejects the victim's relic";
  case RLC_BOUNTY:
    return "Double reward for kills";
  case RLC_REVERSE:
    return "Heal players by attacking";
  case RLC_GOOMBA:
    return "Deal damage by jumping on victims";
  case RLC_SILENT:
    return "You're silent but deaf";
  case RLC_PLAGUE:
    return "Infected with contageous plague";
  case RLC_MINI:
    return "Shrunk to a half of normal size";
  case RLC_TRANSLOCATE:
    return "Exchange location with victim";
  case RLC_UNKNOWN:
    return "Gives random relic when picked up";
  case RLC_PUSH:
    return "Push your victims further";
  case RLC_NORTH:
    return "Acts like the North pole of a magnet";
  case RLC_SOUTH:
    return "Acts like the South pole of a magnet";
  case RLC_FFAKING:
    return "You are the FFA King !";
  default:
    return va( "Missing description for relic %d", relic );
  }
}

/*
==================
RelicShadow
==================
*/
#define SHADOW_DISTANCE   128
#define RELIC_SIZE        15
static qboolean RelicShadow( centity_t *cent, float *shadowPlane, float angle )
{
  vec3_t        end, mins = { -RELIC_SIZE, -RELIC_SIZE, 0 },
                maxs = { RELIC_SIZE, RELIC_SIZE, 2 };
  trace_t       trace;
  float         alpha;
  vec3_t        surfNormal = { 0.0f, 0.0f, 1.0f };

  *shadowPlane = 0;

  if( cg_shadows.integer == 0 )
    return qfalse;

  // send a trace down from the player to the ground
  VectorCopy( cent->lerpOrigin, end );
  VectorMA( cent->lerpOrigin, -SHADOW_DISTANCE, surfNormal, end );
  trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0,
                    MASK_PLAYERSOLID );

  // no shadow if too high
  if( trace.fraction == 1.0 || trace.startsolid || trace.allsolid )
    return qfalse;

  *shadowPlane = trace.endpos[ 2 ] + 1.0f;

  if( cg_shadows.integer != 1 )  // no mark for stencil or projection shadows
    return qtrue;

  // fade the shadow out with height
  alpha = 1.0 - trace.fraction;

  // add the mark as a temporary, so it goes directly to the renderer
  // without taking a spot in the cg_marks array
  CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
     angle, 0.0f, 0.0f, 0.0f, alpha, qfalse, 16.0f, qtrue );
  
  return qtrue;
}

/*
==================
CG_Relic
==================
*/
#define RELIC_Z_OFFSET  16.f
#define RELIC_Z_WOBBLE  3.f
#define RELIC_Z_SPIN    0.1f

void CG_Relic( centity_t *cent )
{
  refEntity_t     ent;
  entityState_t   *es = &cent->currentState;
  vec3_t          origin, angles = { 0, 0, 0 };
  relic_t         relic;
  qboolean        shadow;

  // Relics use modelindex to pass their type
  relic = es->modelindex;
  if( relic < 0 || relic > RLC_NUM_RELICS )
    return;

  // Did this relic just die?
  if( ( es->eFlags & EF_DEAD ) )
  {
    if( CG_IsParticleSystemValid( &cent->relicPS ) || cent->relic )
      return;
    if( BG_GetRelic( &cg.snap->ps ) != RLC_SILENT )
      trap_S_StartSound( NULL, es->number, CHAN_AUTO,
        cgs.media.relicPickupSound );
    cent->relicPS = CG_SpawnNewParticleSystem( cgs.media.relicPickupPS );
    if( CG_IsParticleSystemValid( &cent->relicPS ) )
    {
      CG_SetAttachmentCent( &cent->relicPS->attachment, cent );
      CG_AttachToCent( &cent->relicPS->attachment );
    }
    cent->relic = 1; // set this to prevent the PS from looping
    return;
  }

  // Z-shift and wobble the models up and down a bit
  VectorCopy( cent->lerpOrigin, origin );
  origin[ 2 ] += RELIC_Z_OFFSET + RELIC_Z_WOBBLE *
                 sin( es->number + cg.time / 200.f );

  // Rotate around Z-axis
  angles[ 1 ] = RELIC_Z_SPIN * ( es->number * 1000 + cg.time );

  // Add gear to the scene
  memset ( &ent, 0, sizeof( ent ) );
  VectorCopy( origin, ent.origin );
  VectorCopy( origin, ent.oldorigin );
  ent.hModel = cgs.media.relicGearModel;
  shadow = RelicShadow( cent, &ent.shadowPlane, angles[ 1 ] );
  if( cg_shadows.integer == 3 && shadow )
    ent.renderfx |= RF_SHADOW_PLANE;
  ent.renderfx |= RF_LIGHTING_ORIGIN;
  AnglesToAxis( angles, ent.axis );
  trap_R_AddRefEntityToScene( &ent );

  // Add symbol to the scene
  ent.hModel = cgs.media.relicSymbolModel;
  relic = es->modelindex;
  ent.customShader = cgs.media.relicSymbolShader[ relic ];
  trap_R_AddRefEntityToScene( &ent );

  // Make sure the relic PS marker is reset
  cent->relic = 0;
}
